using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.Media;

namespace OrigPacman
{
	public class Ghost
	{
		public enum States { RUN, ATTACK, DEAD};
        public enum Colors { RED = 0, PURPLE = 1, GREEN = 2, BLUE = 3};
        public enum Direction { NORTH, SOUTH, EAST, WEST, STOP };
		protected Vector2 position = new Vector2(0, 0);
		protected States currentState = States.ATTACK;
		protected Colors currentColor;
		protected int speed = 65;
        protected Direction currentDirection;
        protected int nextWayPoint = 44;
        protected int prevWayPoint = 45;
		protected Texture2D texture;
		protected List<Map.Waypoints> listWayPoints;
		private Random rand;

		//Specify file, instructions, and privelegdes
		//FileStream file = new FileStream("logging.txt", FileMode.Create, FileAccess.Write);
		//StreamWriter sw;
		
        private Map.Waypoints tmpWay;

        #region ghost properties previousley in Ghosts.cs
        public Texture2D Texture
		{
			get { return texture; }
			set { texture = value; }
		}
		public Vector2 Position
		{
			get { return position; }
			set { position = value; }
		}
		public States State
		{
			get { return currentState; }
			set { currentState = value; }
		}
		public Colors Color
		{
			get { return currentColor; }
		}
		public List<Map.Waypoints> Waypoints
		{
			get { return listWayPoints; }
			set
			{
				listWayPoints = value;
				tmpWay = listWayPoints[this.prevWayPoint];
				position = tmpWay.Position;
			}
        }
        #endregion

        //Constructor for Ghost
        public Ghost(Colors ghostColor, Vector2 start)
        {
            currentColor = ghostColor;
            position = start;
            currentState= States.ATTACK;
            currentDirection = Direction.SOUTH;
            speed = 65;
			rand = new Random();
			rand = new Random(rand.Next() + (int)ghostColor * (int)start.X + (int)start.Y);
        }

		#region ghost methods
		public void UpdateGhost(float elapsed, Vector2 pacPosition)
		{
		    //If not at waypoint just update position and move to next
			//Ghost
            if (currentDirection == getDirectionToWaypoint(position, nextWayPoint) && currentDirection != Ghost.Direction.STOP)
            {
                normalUpdate(elapsed);
            }
            else
            {
                // sw.Write(nextWayPoint);
                tmpWay = (Map.Waypoints)listWayPoints[nextWayPoint];
                Vector2 length = (tmpWay.Position - position);
                float distance = length.Length();
                int value;
                value = rand.Next(99);
                //This is in here so the AI can be made random between a wise and a random
                //decision
                if (value < 100)
                {

                    //First check to see if it can continue in the same direction if the random number is between 1 and 25
                    if (value < 50)
                    {
                        //Check to see if ghost can continue in same direction
                        switch (currentDirection)
                        {
                            case Ghost.Direction.EAST:
                                if (tmpWay.Right < listWayPoints.Count - 1)
                                {
                                    int tmp = nextWayPoint;
                                    nextWayPoint = tmpWay.Right;
                                    prevWayPoint = tmp;
                                    position = new Vector2(tmpWay.Position.X + distance + (speed * elapsed), tmpWay.Position.Y);
                                    return;
                                }
                                break;
                            case Ghost.Direction.NORTH:
                                if (tmpWay.Up < listWayPoints.Count - 1)
                                {
                                    int tmp = nextWayPoint;
                                    nextWayPoint = tmpWay.Up;
                                    this.prevWayPoint = tmp;
                                    position = new Vector2(tmpWay.Position.X, tmpWay.Position.Y - (distance + (speed * elapsed)));
                                    return;
                                }
                                break;
                            case Ghost.Direction.SOUTH:
                                if (tmpWay.Down < listWayPoints.Count - 1)
                                {
                                    int tmp = nextWayPoint;
                                    nextWayPoint = tmpWay.Down;
                                    this.prevWayPoint = tmp;
                                    position = new Vector2(tmpWay.Position.X, tmpWay.Position.Y + distance + (speed * elapsed));
                                    return;
                                }
                                break;
                            case Ghost.Direction.WEST:
                                if (tmpWay.Left < listWayPoints.Count - 1)
                                {
                                    int tmp = nextWayPoint;
                                    nextWayPoint = tmpWay.Left;
                                    this.prevWayPoint = tmp;
                                    position = new Vector2(tmpWay.Position.X - (distance + (speed * elapsed)), tmpWay.Position.Y);
                                    return;
                                }
                                break;
                        }//End switch
                    }
                    //If not move in a random direction
                    //Random Move
                    value = rand.Next(0, 3);
                    RandomMove(value);
                }//End if
            }
		}
        public void RandomMove(int caseValue)
        {
            switch (caseValue)
            {
                case 0://Move WEST
                    if (tmpWay.Left < 90)
                    {
                        int tmp = nextWayPoint;
                        nextWayPoint = tmpWay.Left;
                        this.prevWayPoint = tmp;
                        currentDirection = Ghost.Direction.WEST;
                    }
                    else //Pick another direction
                    {
                        currentDirection = getNextDirection(currentDirection);
                        while (!tryNextDirection())
                        {
                            currentDirection = getNextDirection(currentDirection);
                        }
                        setNewPoints();
                    }
                    break;
                case 1: //EAST
                    if (tmpWay.Right < 90)
                    {
                        int tmp = nextWayPoint;
                        nextWayPoint = tmpWay.Right;
                        prevWayPoint = tmp;
                        currentDirection = Ghost.Direction.EAST;
                    }
                    else
                    {
                        currentDirection = getNextDirection(currentDirection);
                        while (!tryNextDirection())
                        {
                            currentDirection = getNextDirection(currentDirection);
                        }
                        setNewPoints();
                    }
                    break;
                case 2:  //South
                    if (tmpWay.Down < 90)
                    {
                        int tmp = nextWayPoint;
                        nextWayPoint = tmpWay.Down;
                        this.prevWayPoint = tmp;
                        currentDirection = Ghost.Direction.SOUTH;
                    }
                    else
                    {
                        currentDirection = getNextDirection(currentDirection);
                        while (!tryNextDirection())
                        {
                            currentDirection = getNextDirection(currentDirection);
                        }
                        setNewPoints();
                    }
                    break;
                case 3:
                    if (tmpWay.Up < 90)
                    {
                        int tmp = nextWayPoint;
                        nextWayPoint = tmpWay.Up;
                        this.prevWayPoint = tmp;
                        currentDirection = Ghost.Direction.NORTH;
                    }
                    else
                    {
                        currentDirection = getNextDirection(currentDirection);
                        while (!tryNextDirection())
                        {
                            currentDirection = getNextDirection(currentDirection);
                        }
                        setNewPoints();
                    }
                    break;
            }//End Switch
        }

		public void RenderGhost(ref SpriteBatch sprite)
		{
			int x = (int)position.X - 16;
			int y = (int)position.Y - 16;
			sprite.Draw(texture, new Rectangle(x, y, 32, 32), Microsoft.Xna.Framework.Graphics.Color.White);
		}

		/*void setWaypoints(List<Map.Waypoints> list)
		{
			listWayPoints = list;
			tmpWay = listWayPoints[this.prevWayPoint];
			position = tmpWay.Position;
		}*/

		//===========================================
		//Returns Direction of Next Waypoint
		//===========================================
		private Ghost.Direction getDirectionToWaypoint(Vector2 pos, int nextWayIndex)
		{
			if (nextWayIndex > listWayPoints.Count - 1)
				return Ghost.Direction.STOP;
			tmpWay = listWayPoints[nextWayIndex];
			Vector2 vec = tmpWay.Position - pos;
			vec.Normalize();
			if (vec.X < 0.45f && vec.X > -0.45f)
			{
				vec.X = 0.0f;
			}
			if (vec.X < -0.5f)
			{
				vec.X = -1.0f;
				vec.Y = 0.0f;
			}
			if (vec.X > 0.5)
			{
				vec.X = 1.0f;
				vec.Y = 0.0f;
			}
			if (vec.Y < 0.45f && vec.Y > -0.45f)
			{
				vec.Y = 0.0f;
			}
			if (vec.Y > 0.5)
			{
				vec.Y = 1.0f;
				vec.X = 0.0f;
			}
			if (vec.Y < -0.5f)
			{
				vec.Y = -1.0f;
				vec.X = 0.0f;
			}
			if (vec.X == 1.0f)
				return Ghost.Direction.EAST;
			else if (vec.X == -1.0f)
				return Ghost.Direction.WEST;
			else if (vec.Y == 1.0f)
				return Ghost.Direction.SOUTH;
			else if (vec.Y == -1.0f)
				return Ghost.Direction.NORTH;
			return Ghost.Direction.STOP;
		}
		private Ghost.Direction reverseDirection(/*Ghost.Direction dir*/)
		{
			if (currentDirection == Ghost.Direction.EAST)
				return Ghost.Direction.WEST;
			if (currentDirection == Ghost.Direction.NORTH)
				return Ghost.Direction.SOUTH;
			if (currentDirection == Ghost.Direction.SOUTH)
				return Ghost.Direction.NORTH;
			if (currentDirection == Ghost.Direction.WEST)
				return Ghost.Direction.EAST;

			return Ghost.Direction.STOP;
		}
		private Ghost.Direction getRelativeDirection(Vector2 pac)
		{
			//Calculate the greatest distance between pacman and ghost
			float Ydifference = pac.Y - position.Y;
			float Xdifference = pac.X - position.X;
			if (pac.Y > position.Y && Ydifference > Xdifference)
				return Ghost.Direction.SOUTH;
			if (pac.Y < position.Y && Ydifference > Xdifference)
				return Ghost.Direction.NORTH;
			if (pac.X > position.X && Xdifference > Ydifference)
				return Ghost.Direction.EAST;
			if (pac.X < position.X && Xdifference > Ydifference)
				return Ghost.Direction.WEST;
			return Ghost.Direction.WEST;
		}
		private Ghost.Direction getNextDirection(Ghost.Direction dir)
		{
			if (dir == Ghost.Direction.WEST)
				return Ghost.Direction.NORTH;
			if (dir == Ghost.Direction.NORTH)
				return Ghost.Direction.EAST;
			if (dir == Ghost.Direction.EAST)
				return Ghost.Direction.SOUTH;
			if (dir == Ghost.Direction.SOUTH)
				return Ghost.Direction.WEST;
			if (dir == Ghost.Direction.STOP)
				return Ghost.Direction.EAST;

			return Ghost.Direction.STOP;
		}
		private bool tryNextDirection()
		{
			Map.Waypoints tmp = (Map.Waypoints)listWayPoints[nextWayPoint];
			switch (currentDirection)
			{
				case Ghost.Direction.EAST:
					if (tmp.Right < listWayPoints.Count - 1)
						return true;
					break;
				case Ghost.Direction.NORTH:
					if (tmp.Up < listWayPoints.Count - 1)
						return true;
					break;
				case Ghost.Direction.SOUTH:
					if (tmp.Down < listWayPoints.Count - 1)
						return true;
					break;
				case Ghost.Direction.WEST:
					if (tmp.Left < listWayPoints.Count - 1)
						return true;
					break;
			}
			return false;
		}
		private void setNewPoints()
		{
			if (nextWayPoint > listWayPoints.Count - 1 || nextWayPoint < 0)
				return;
			Map.Waypoints tmp = (Map.Waypoints)listWayPoints[nextWayPoint];
			int prev;
			switch (currentDirection)
			{
				case Ghost.Direction.EAST:
					prev = nextWayPoint;
					nextWayPoint = tmp.Right;
					prevWayPoint = prev;
					break;
				case Ghost.Direction.NORTH:
					prev = nextWayPoint;
					nextWayPoint = tmp.Up;
					prevWayPoint = prev;
					break;
				case Ghost.Direction.SOUTH:
					prev = nextWayPoint;
					nextWayPoint = tmp.Down;
					prevWayPoint = prev;
					break;
				case Ghost.Direction.WEST:
					prev = nextWayPoint;
					nextWayPoint = tmp.Left;
					prevWayPoint = prev;
					break;
			}
		}
		private void normalUpdate(float elapsed)
		{
			//Update Direction
			if (currentDirection == Ghost.Direction.EAST)
			{
				position = new Vector2(position.X + (speed * elapsed), position.Y);
			}
			if (currentDirection == Ghost.Direction.NORTH)
			{
				position = new Vector2(position.X, position.Y - (speed * elapsed));
			}
			if (currentDirection == Ghost.Direction.SOUTH)
			{
				position = new Vector2(position.X, position.Y + (speed * elapsed));
			}
			if (currentDirection == Ghost.Direction.WEST)
			{
				position = new Vector2(position.X - (speed * elapsed), position.Y);
			}
		}

		#endregion
	}
}
